在進入實戰部署腳本之前,我們需要升級我們的 Jenkins Shared Library。為了支撐 AI 時代的高產出,我們的 Pipeline 不能只是一連串死板的指令,而應該是「元數據驅動 (Metadata-Driven)」的靈活系統。本篇將介紹如何設計一個結構化的共享庫來管理多專案的 CI/CD。
當團隊同時開發幾十個微服務時,每個專案的技術棧可能不同(有的用 .NET 8,有的用 Node.js),部署目標也不同。與其在每個專案寫 if-else,不如建立一個中心化的「配置表」,讓 Pipeline 根據專案特性自動調整行為。
我們在 vars/ 目錄中定義一個 project.groovy,作為所有專案的中央註冊表。
// vars/project.groovy
def repos() {
return [
'user-service': [
repo_url: 'https://gitlab.com/my-org/user-service.git',
sq_key: 'org_user_service',
build_type: 'dotnet',
solution: 'UserService.sln',
deploy_target: 'win-server-01'
],
'auth-portal': [
repo_url: 'https://gitlab.com/my-org/auth-portal.git',
sq_key: 'org_auth_portal',
build_type: 'nodejs',
project_dir: 'src/client',
deploy_target: 'win-server-02'
]
]
}
// 輔助函式:根據專案 ID 獲取配置
def getConfig(String projectId) {
def allRepos = repos()
if (allRepos.containsKey(projectId)) {
return allRepos[projectId]
}
error "Project ${projectId} is not registered in Shared Library!"
}
雖然 vars/ 適合放簡單的指令,但複雜的邏輯建議放在 src/ 下的 Groovy 類別中,這能提供更好的類型檢查與封裝。
package com.example
class ConfigManager implements Serializable {
def script
ConfigManager(script) {
this.script = script
}
def getVaultPath(String env, String projectId) {
return "secret/data/deploy/${env}/${projectId}"
}
}
引入共享庫後,專案方的 Jenkinsfile 會變得非常簡潔,因為它只專注於「我是誰」以及「我要去哪」。
@Library('my-shared-library') _
// 獲取目前專案在配置表中的定義
def config = project.getConfig('user-service')
pipeline {
agent { label config.build_type } // 動態選擇 Agent
stages {
stage('Initialize') {
steps {
script {
echo "Initializing pipeline for ${config.sq_key}..."
// 初始化環境變數,後續步驟可直接使用
env.PROJECT_SQ_KEY = config.sq_key
}
}
}
// 後續步驟可根據 config.build_type 分歧執行不同的建置函式
}
}
透過這種設計,我們將「邏輯 (How)」與「數據 (What)」徹底分離:
vars/ 與 src/。project.groovy 的 Map 中。當 AI 生成一個新專案時,DevOps 工程師只需在 project.groovy 增加幾行配置,該專案就立即獲得了全套的 CI/CD 能力。下一步,我們將實作具備此能力的 sonarqube.jenkinsfile。